/*
 * periph.cpp
 *
 *  Created on: Dec 3, 2012
 *      Author: r.leonov
 */

#include "periph.h"
#include "kl_lib.h"
#include "led.h"
#include "usb.h"

dConfig_t Type;
Device_t Device;
Buf_t BufToHost, BufToPeriph, BufToSend;
LedBlink_t TxLed, RxLed;
UART_SETTINGS UartSettings;
uint8_t UartSettingsContanier[] = {
    0x20,           //  }
    0xA1,           //  }   500000 Baud
    0x07,           //  }
    0x00,
    0x00,
    0x00,
    0x08            // WordLength - 9
};


void Device_t::Config(dConfig_t ADeviceConfig){
    ParseParametres(UartSettingsContanier);
    switch (ADeviceConfig) {
        case dtDefault: // Default
            UsartPeriph.Init();
            CmdUnit.Printf("Default: %u\r", UartSettings.Baudrate);
            break;
        case dtCOM_Port: // User COM port
            UsartPeriph.Init();
            CmdUnit.Printf("Com_Port: %u\r", UartSettings.Baudrate);
            break;
        case dtSPI_Line: // SPI Line
            CmdUnit.Printf("SPI_Line\r");
            break;
        case dtI2C_Line: // I2C Line
            CmdUnit.Printf("I2C_Line\r");
            break;
    }
    IsConfigured = true;
}

void Device_t::ParseParametres(uint8_t* PBuf){
    // Write down a baudrate value in UartSettings struct
    UartSettings.Baudrate = PBuf[2];
    UartSettings.Baudrate <<= 8;
    UartSettings.Baudrate |= PBuf[1];
    UartSettings.Baudrate <<= 8;
    UartSettings.Baudrate |= PBuf[0];

    UartSettings.StopBits = PBuf[4];
    UartSettings.Parity = PBuf[5];
    UartSettings.WordLength = PBuf[6];
}

// ============================= USART PERIPH ==================================

Usart_t UsartPeriph;

void Usart_t::Init() {
    USART_DeInit(USART2);
    // Rx buf pointer description
    BufToHost.PBuf = BufToHost.Buf;
    BufToHost.PWIndx = &BufToHost.WIndx;
    BufToHost.PRIndx = &BufToHost.RIndx;
    // Tx buf pointer description
    BufToPeriph.PBuf = BufToPeriph.Buf;
    BufToPeriph.PWIndx = &BufToPeriph.WIndx;
    BufToPeriph.PRIndx = &BufToPeriph.RIndx;
    // Send buf pointer
    BufToSend.PBuf = BufToSend.Buf;
    BufToSend.PWIndx = &BufToSend.WIndx;
    BufToSend.PRIndx = &BufToSend.RIndx;

    INeedToTransmit = 0;


    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);      // USART2 clock
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    // ==== GPIO init ====
    klPinSetup(GPIOA, 2, pmOutAFPushPull);      // TX2
    klPinSetup(GPIOA, 3, pmInPullUp);         // RX2

    // ==== USART configuration ====
    USART_InitTypeDef USART_InitStructure;
    USART_InitStructure.USART_BaudRate = UartSettings.Baudrate;
    switch (UartSettings.WordLength) { 	// Set Word_Length
        case 0x08:
            USART_InitStructure.USART_WordLength = USART_WordLength_8b;
            break;
        case 0x09:
            USART_InitStructure.USART_WordLength = USART_WordLength_9b;
            break;
    }
    switch (UartSettings.StopBits) { 	// Set Stop Bits
        case 0x00:
            USART_InitStructure.USART_StopBits = USART_StopBits_1;
            break;
        case 0x01:
            USART_InitStructure.USART_StopBits = USART_StopBits_0_5;
            break;
        case 0x02:
            USART_InitStructure.USART_StopBits = USART_StopBits_1_5;
            break;
        case 0x03:
            USART_InitStructure.USART_StopBits = USART_StopBits_2;
            break;
    };
    switch (UartSettings.Parity) {      // Set Parity
        case 0x00:
            USART_InitStructure.USART_Parity = USART_Parity_No;
            break;
    }
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART2, &USART_InitStructure);

    // ==== DMA ====
    DMA_InitTypeDef DMA_InitStructure;
    DMA_DeInit(USART_PERIPH_DMA_CNL);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &USART2->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t) BufToHost.PBuf;
    DMA_InitStructure.DMA_BufferSize         = USART_PERIPH_BUF_SIZE;
    DMA_InitStructure.DMA_Priority           = DMA_Priority_High;
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;
    DMA_Init(USART_PERIPH_DMA_CNL, &DMA_InitStructure);
    // Start DMA
    USART_DMACmd(USART2, USART_DMAReq_Tx, DISABLE);
    DMA_Cmd(USART_PERIPH_DMA_CNL, DISABLE);

    // ==== NVIC ====
    NVIC_InitTypeDef NVIC_InitStructure;
    // Enable the USART Interrupt
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    // Disable RX interrupt
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);

    USART_Cmd(USART2, ENABLE);
}

void Usart_t::Task(void) {
    // If Buf to Host have data to send
    if(!BufToHost.WasRead()){
        BufToSend.Write(BufToHost.Read());
        INeedToTransmit++;
    }
    else if(INeedToTransmit != 0){
//        CmdUnit.Printf("Send: %A\r", BufToSend.PBuf, INeedToTransmit);
        Usb.Send(1, BufToSend.PBuf, INeedToTransmit);
        *BufToHost.PRIndx = *BufToHost.PWIndx;
        BufToSend.Clear();
        INeedToTransmit = 0;
        TxLed.Blink(13);
    }
    // If buf to Periph has data to send
    if (!BufToPeriph.WasRead()) {
        UsartPeriph.Send(BufToPeriph.Read());
        RxLed.Blink(13);
//        CmdUnit.Printf("TP: %X\r", BufToPeriph.Read());
    }
//    // ECHO
//    if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET) return;
//    uint8_t b = USART_ReceiveData(USART2);
}

void USART2_IRQHandler() {
    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) {
        BufToHost.Write(USART2->DR);
//        UsartPeriph.Send(USART2->DR);
        USART_ClearITPendingBit(USART2, USART_IT_RXNE);
    }
}
